#include "include/DemoDAO.h"
#include <pqxx/pqxx>
#include <iostream>
#include <stdexcept>

#ifdef _WIN32
#define DEMO_LIB_BUILD
#endif

// 实现类定义
class DemoDAOImpl {
public:
    std::string connection_string;
    std::unique_ptr<pqxx::connection> conn;
    mutable std::string last_error;

    explicit DemoDAOImpl(const std::string& conn_str) 
        : connection_string(conn_str) {
        initializeConnection();
    }

    // 移除显式的 close() 调用，让 unique_ptr 自动管理
    ~DemoDAOImpl() = default;

    bool initializeConnection() {
        try {
            conn = std::make_unique<pqxx::connection>(connection_string);
            if (conn->is_open()) {
                std::cout << "Connected to database: " << conn->dbname() << std::endl;
                last_error.clear();
                return true;
            } else {
                last_error = "Failed to connect to database";
                std::cerr << last_error << std::endl;
                return false;
            }
        } catch (const std::exception& e) {
            last_error = std::string("Connection error: ") + e.what();
            std::cerr << last_error << std::endl;
            return false;
        }
    }

    bool isConnected() const {
        return conn && conn->is_open();
    }

    bool reconnect() {
        // 直接重置连接对象，让 RAII 处理清理
        conn.reset();
        return initializeConnection();
    }

    std::string getLastError() const {
        return last_error;
    }

    bool createTable() {
        if (!isConnected()) {
            last_error = "Not connected to database";
            std::cerr << last_error << std::endl;
            return false;
        }

        try {
            pqxx::work txn(*conn);
            
            std::string sql = R"(
                CREATE TABLE IF NOT EXISTS demo (
                    id SERIAL PRIMARY KEY,
                    data TEXT NOT NULL,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
            )";
            
            txn.exec(sql);
            txn.commit();
            std::cout << "Table created successfully!" << std::endl;
            last_error.clear();
            return true;
        } catch (const std::exception& e) {
            last_error = std::string("Error creating table: ") + e.what();
            std::cerr << last_error << std::endl;
            return false;
        }
    }

    int insertData(const std::string& data) {
        if (!isConnected()) {
            last_error = "Not connected to database";
            std::cerr << last_error << std::endl;
            return -1;
        }

        try {
            pqxx::work txn(*conn);
            
            std::string sql = "INSERT INTO demo (data) VALUES ($1) RETURNING id";
            pqxx::result result = txn.exec_params(sql, data);
            txn.commit();
            
            int id = result[0][0].as<int>();
            std::cout << "Inserted record with ID: " << id << std::endl;
            last_error.clear();
            return id;
        } catch (const std::exception& e) {
            last_error = std::string("Error inserting data: ") + e.what();
            std::cerr << last_error << std::endl;
            return -1;
        }
    }

    void batchInsert(const std::vector<std::string>& dataList) {
        if (!isConnected()) {
            last_error = "Not connected to database";
            std::cerr << last_error << std::endl;
            return;
        }

        try {
            pqxx::work txn(*conn);
            
            for (const auto& data : dataList) {
                txn.exec_params("INSERT INTO demo (data) VALUES ($1)", data);
            }
            
            txn.commit();
            std::cout << "Batch inserted " << dataList.size() << " records" << std::endl;
            last_error.clear();
        } catch (const std::exception& e) {
            last_error = std::string("Error in batch insert: ") + e.what();
            std::cerr << last_error << std::endl;
        }
    }

    void selectAll() {
        if (!isConnected()) {
            last_error = "Not connected to database";
            std::cerr << last_error << std::endl;
            return;
        }

        try {
            pqxx::work txn(*conn);
            
            std::string sql = "SELECT id, data, created_at FROM demo ORDER BY id";
            pqxx::result result = txn.exec(sql);
            
            std::cout << "\n=== All Records ===" << std::endl;
            for (const auto& row : result) {
                std::cout << "ID: " << row["id"].as<int>()
                          << ", Data: " << row["data"].as<std::string>()
                          << ", Created: " << row["created_at"].as<std::string>()
                          << std::endl;
            }
            std::cout << "Total: " << result.size() << " records" << std::endl;
            last_error.clear();
        } catch (const std::exception& e) {
            last_error = std::string("Error selecting data: ") + e.what();
            std::cerr << last_error << std::endl;
        }
    }

    void selectById(int id) {
        if (!isConnected()) {
            last_error = "Not connected to database";
            std::cerr << last_error << std::endl;
            return;
        }

        try {
            pqxx::work txn(*conn);
            
            std::string sql = "SELECT id, data, created_at FROM demo WHERE id = $1";
            pqxx::result result = txn.exec_params(sql, id);
            
            if (result.empty()) {
                std::cout << "No record found with ID: " << id << std::endl;
            } else {
                const auto& row = result[0];
                std::cout << "\n=== Record Details ===" << std::endl;
                std::cout << "ID: " << row["id"].as<int>()
                          << ", Data: " << row["data"].as<std::string>()
                          << ", Created: " << row["created_at"].as<std::string>()
                          << std::endl;
            }
            last_error.clear();
        } catch (const std::exception& e) {
            last_error = std::string("Error selecting data by ID: ") + e.what();
            std::cerr << last_error << std::endl;
        }
    }

    bool updateData(int id, const std::string& newData) {
        if (!isConnected()) {
            last_error = "Not connected to database";
            std::cerr << last_error << std::endl;
            return false;
        }

        try {
            pqxx::work txn(*conn);
            
            std::string sql = "UPDATE demo SET data = $1 WHERE id = $2";
            pqxx::result result = txn.exec_params(sql, newData, id);
            txn.commit();
            
            if (result.affected_rows() > 0) {
                std::cout << "Updated record with ID: " << id << std::endl;
                last_error.clear();
                return true;
            } else {
                std::cout << "No record found with ID: " << id << std::endl;
                last_error = "No record found with ID: " + std::to_string(id);
                return false;
            }
        } catch (const std::exception& e) {
            last_error = std::string("Error updating data: ") + e.what();
            std::cerr << last_error << std::endl;
            return false;
        }
    }

    bool deleteData(int id) {
        if (!isConnected()) {
            last_error = "Not connected to database";
            std::cerr << last_error << std::endl;
            return false;
        }

        try {
            pqxx::work txn(*conn);
            
            std::string sql = "DELETE FROM demo WHERE id = $1";
            pqxx::result result = txn.exec_params(sql, id);
            txn.commit();
            
            if (result.affected_rows() > 0) {
                std::cout << "Deleted record with ID: " << id << std::endl;
                last_error.clear();
                return true;
            } else {
                std::cout << "No record found with ID: " << id << std::endl;
                last_error = "No record found with ID: " + std::to_string(id);
                return false;
            }
        } catch (const std::exception& e) {
            last_error = std::string("Error deleting data: ") + e.what();
            std::cerr << last_error << std::endl;
            return false;
        }
    }
};

// DemoDAO 类实现
DemoDAO::DemoDAO(const std::string& conn_str) 
    : pImpl(std::make_unique<DemoDAOImpl>(conn_str)) {
}

DemoDAO::~DemoDAO() = default;

DemoDAO::DemoDAO(DemoDAO&&) noexcept = default;
DemoDAO& DemoDAO::operator=(DemoDAO&&) noexcept = default;

bool DemoDAO::createTable() {
    return pImpl->createTable();
}

int DemoDAO::insertData(const std::string& data) {
    return pImpl->insertData(data);
}

void DemoDAO::batchInsert(const std::vector<std::string>& dataList) {
    pImpl->batchInsert(dataList);
}

void DemoDAO::selectAll() {
    pImpl->selectAll();
}

void DemoDAO::selectById(int id) {
    pImpl->selectById(id);
}

bool DemoDAO::updateData(int id, const std::string& newData) {
    return pImpl->updateData(id, newData);
}

bool DemoDAO::deleteData(int id) {
    return pImpl->deleteData(id);
}

bool DemoDAO::isConnected() const {
    return pImpl->isConnected();
}

bool DemoDAO::reconnect() {
    return pImpl->reconnect();
}

std::string DemoDAO::getLastError() const {
    return pImpl->getLastError();
}